package com.googlecode.openrtp.spi.rtcp;

import java.io.UnsupportedEncodingException;
import java.util.EnumMap;
import java.util.Map;
import com.googlecode.openrtp.spi.PacketUtil;
import static com.googlecode.openrtp.spi.rtcp.SourceDescriptionType.*;

/**
 *
 * @author jocke
 */
public class SourceDescription {

    private final String cname;
    private final String name;
    private final String email;
    private final String phone;
    private final String loc;
    private final String tool;
    private final String note;
    private final String priv;

    private SourceDescription(String cname, String name, String email, String phone, String loc, String tool, String note, String priv) {
        this.cname = cname;
        this.name = name;
        this.email = email;
        this.phone = phone;
        this.loc = loc;
        this.tool = tool;
        this.note = note;
        this.priv = priv;
    }

    public static SourceDescription fromMap(Map<SourceDescriptionType, String> descs) {
        return new SourceDescription(
                lookup(descs, CNAME),
                lookup(descs, NAME),
                lookup(descs, EMAIL),
                lookup(descs, PHONE),
                lookup(descs, LOC),
                lookup(descs, TOOL),
                lookup(descs, NOTE),
                lookup(descs, PRIV));
    }

    private static String lookup(Map<SourceDescriptionType, String> descs, SourceDescriptionType type) {
        return descs.get(type);
    }

    public static Map<SourceDescriptionType, String> toMap(SourceDescription description) {
        Map<SourceDescriptionType, String> descs = new EnumMap<SourceDescriptionType, String>(SourceDescriptionType.class);
        putIfNotNull(descs, CNAME, description.getCname());
        putIfNotNull(descs, NAME, description.getName());
        putIfNotNull(descs, EMAIL, description.getEmail());
        putIfNotNull(descs, PHONE, description.getPhone());
        putIfNotNull(descs, LOC, description.getLoc());
        putIfNotNull(descs, TOOL, description.getTool());
        putIfNotNull(descs, NOTE, description.getNote());
        putIfNotNull(descs, PRIV, description.getPriv());
        return descs;
    }

    private static void putIfNotNull(Map<SourceDescriptionType, String> data, SourceDescriptionType type, String txt) {
        if (txt != null) {
            data.put(type, txt);
        }
    }

    public String getCname() {
        return cname;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getPhone() {
        return phone;
    }

    public String getLoc() {
        return loc;
    }

    public String getTool() {
        return tool;
    }

    public String getNote() {
        return note;
    }

    public String getPriv() {
        return priv;
    }

    public int getChunkLength() throws UnsupportedEncodingException {
        int length = 0;
        Map<SourceDescriptionType, String> map = toMap(this);
        length += 4; //ssrcs
        for (Map.Entry<SourceDescriptionType, String> entry : map.entrySet()) {
            length += 1; //type 
            length += 1; // length
            length += entry.getValue().getBytes("UTF-8").length; //text
        }
        length += 1; // The end of the list,
        length += PacketUtil.findWordBoundry(length); //Find closest divisor of 32 bits
        
        return length;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 37 * hash + (this.cname != null ? this.cname.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SourceDescription other = (SourceDescription) obj;
        if ((this.cname == null) ? (other.cname != null) : !this.cname.equals(other.cname)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "SourceDescription{" + "cname=" + cname + ", name=" + name + ", email=" + email + ", phone=" + phone + ", loc=" + loc + ", tool=" + tool + ", note=" + note + ", priv=" + priv + '}';
    }
}
